package com.anywhere.freightman.order.service.impl;

import com.anywhere.freightman.car.model.CarModel;
import com.anywhere.freightman.car.model.DriverModel;
import com.anywhere.freightman.car.service.ICarService;
import com.anywhere.freightman.car.service.IDriverService;
import com.anywhere.freightman.common.BaseEntityService;
import com.anywhere.freightman.common.BaseMapper;
import com.anywhere.freightman.common.entity.ReportDayCount;
import com.anywhere.freightman.common.entity.order.DriverCarEntity;
import com.anywhere.freightman.common.entity.order.WaybillQueryEntity;
import com.anywhere.freightman.common.entity.user.Account;
import com.anywhere.freightman.common.enumeration.*;
import com.anywhere.freightman.common.ex.CustomException;
import com.anywhere.freightman.external.controller.request.ExOrderRequest;
import com.anywhere.freightman.order.controller.request.WaybillOneRequest;
import com.anywhere.freightman.order.controller.request.WaybillRequest;
import com.anywhere.freightman.order.dao.WaybillDao;
import com.anywhere.freightman.order.dao.WaybillFileDao;
import com.anywhere.freightman.order.model.*;
import com.anywhere.freightman.order.service.IAddressBookService;
import com.anywhere.freightman.order.service.IGoodsService;
import com.anywhere.freightman.order.service.IWaybillLogService;
import com.anywhere.freightman.order.service.IWaybillService;
import com.anywhere.freightman.system.service.IFileService;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Transactional
public class WaybillService extends BaseEntityService<WaybillModel, WaybillQueryEntity> implements IWaybillService {

    @Autowired
    private WaybillDao waybillDao;
    @Autowired
    private IWaybillLogService waybillLogService;
    @Autowired
    private ICarService carService;
    @Autowired
    private IDriverService driverService;
    @Autowired
    private IAddressBookService addressBookService;
    @Autowired
    private WaybillFileDao waybillFileDao;
    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private IFileService fileService;

    @Override
    public BaseMapper<WaybillModel> getBaseDao() {
        return waybillDao;
    }

    @Override
    public Example getExample(WaybillQueryEntity entity) {
        Weekend<WaybillModel> weekend = Weekend.of(WaybillModel.class);
        WeekendCriteria<WaybillModel, Object> criteria = weekend.weekendCriteria();

        if (entity == null) {
            return weekend;
        }

        if (entity.getCompanyId() != null) {
            criteria.andEqualTo("companyId", entity.getCompanyId());
        }

        if (!StringUtils.isEmpty(entity.getNo())) {
            criteria.andLike("no", "%" + entity.getNo() + "%");
        }

        return weekend;
    }

    @Override
    public WaybillModel getByNo(String orderNo) {
        return waybillDao.getByNo(orderNo);
    }

    @Override
    public WaybillModel getByCode(String code) {
        return null;
    }

    @Override
    public void updateCode(String orderNo) {
        WaybillModel model = getByNo(orderNo);
        if (model != null) {
            model.setCode(getRandomCode());
            update(model);
        }
    }

    @Override
    public void close(String orderNo) {
        WaybillModel waybill = getByNo(orderNo);
        if (waybill == null) {
            throw new CustomException("订单信息不存在");
        }

        ArrayList<WaybillStatus> statuses = Lists.newArrayList(WaybillStatus.CREATED, WaybillStatus.WAIT_PICK, WaybillStatus.PICKED);
        if (!statuses.contains(waybill.getStatus())) {
            throw new CustomException("订单无法取消");
        }

        waybill.setStatus(WaybillStatus.CANCEL);
        waybill.setDoneTime(new Date());
        update(waybill);

        List<DriverCarEntity> list = getListCarAndDriver(orderNo);
        for (DriverCarEntity item : list) {
            driverService.changeStatus(item.getDriverId(), DriverStatus.IDLE);
        }

        waybillLogService.insert(orderNo, "订单已经被取消");
    }

    @Override
    public List<DriverCarEntity> getListCarAndDriver(String orderNo) {
        return waybillDao.getListCarAndDriver(orderNo);
    }

    @Override
    public void accessCarAndDriver(String orderNo, Long carId, Long driverId, double price) {
        waybillDao.accessCarAndDriver(orderNo, carId, driverId, price);
    }

    @Override
    public void bindCarAndDriver(String orderNo, Long carId, Long driverId) {
        bindCarAndDriver(orderNo, carId, driverId, 0);
    }

    @Override
    public void bindCarTrailerAndDriver(String orderNo, Long carId, Long driverId, Long trailerId) {
        WaybillModel model = getByNo(orderNo);
        if (model == null) {
            throw new CustomException("运单信息不存在");
        }

        CarModel carModel = carService.getById(carId);
        if (carModel == null) {
            throw new CustomException("车辆信息不存在");
        }

        DriverModel driverModel = driverService.getById(driverId);
        if (driverModel == null) {
            throw new CustomException("司机信息不存在");
        }

        List<DriverCarEntity> carAndDriverList = getListCarAndDriver(orderNo);
        for (DriverCarEntity item : carAndDriverList) {
            if (item.getCarId().equals(carId)) {
                throw new CustomException("车辆已经添加，请不要重复操作");
            }
            if (item.getDriverId().equals(driverId)) {
                throw new CustomException("司机已经添加，请不要重复操作");
            }
        }

        waybillDao.insertCarAndDriver(orderNo, carId, driverId, trailerId, 0.0);

        if (model.getType().equals(WaybillType.DIRECT)) {
            String content = String.format("指派司机[%s],指派车辆[%s]", driverModel.getRealName(), carModel.getCarNumber());
            waybillLogService.insert(orderNo, content);
        } else {
            String content = String.format("司机[%s-%s]接单", driverModel.getRealName(), carModel.getCarNumber());
            waybillLogService.insert(orderNo, content);
        }
    }

    @Override
    public void bindCarAndDriver(String orderNo, Long carId, Long driverId, double price) {
        WaybillModel model = getByNo(orderNo);
        if (model == null) {
            throw new CustomException("运单信息不存在");
        }

        CarModel carModel = carService.getById(carId);
        if (carModel == null) {
            throw new CustomException("车辆信息不存在");
        }

        DriverModel driverModel = driverService.getById(driverId);
        if (driverModel == null) {
            throw new CustomException("司机信息不存在");
        }

        List<DriverCarEntity> carAndDriverList = getListCarAndDriver(orderNo);
        for (DriverCarEntity item : carAndDriverList) {
            if (item.getCarId().equals(carId)) {
                throw new CustomException("车辆已经添加，请不要重复操作");
            }
            if (item.getDriverId().equals(driverId)) {
                throw new CustomException("司机已经添加，请不要重复操作");
            }
        }

        waybillDao.insertCarAndDriver(orderNo, carId, driverId, null, price);

        if (model.getType().equals(WaybillType.DIRECT)) {
            String content = String.format("指派司机[%s],指派车辆[%s]", driverModel.getRealName(), carModel.getCarNumber());
            waybillLogService.insert(orderNo, content);
        } else {
            String content = String.format("司机[%s-%s]接单", driverModel.getRealName(), carModel.getCarNumber());
            waybillLogService.insert(orderNo, content);
        }
    }

    @Override
    public void accessCarDriver(long id, Account account) {
        CarDriverModel carDriverModel = waybillDao.getCarDriverModel(id);
        if (carDriverModel != null) {
            WaybillModel waybill = getByNo(carDriverModel.getOrderNo());
            if (waybill == null || (!account.getType().equals(RoleType.ADMIN)
                    && !account.getCompanyId().equals(waybill.getCompanyId()))) {
                throw new CustomException("运单信息不存在");
            }

            DriverModel driverModel = driverService.getById(carDriverModel.getDriverId());
            if (driverModel != null) {
                /*String content = String.format("接受司机[%s]报价", driverModel.getRealName());
                waybillLogService.insert(carDriverModel.getOrderNo(), content);*/

                waybillDao.saveCarDriverModel(id, AcceptedState.ACCEPTED);
                waybillDao.removeCarDriverWithNoAccepted(waybill.getNo());
            } else {
                throw new CustomException("司机信息不存在");
            }
        }


    }

    @Override
    public void removeCarAndDriver(Long id) {
        waybillDao.deleteCarDriver(id);
    }

    @Override
    public WaybillModel insert(WaybillRequest request, Long companyId) {
        WaybillModel model = new WaybillModel();
        BeanUtils.copyProperties(request, model);
        model.setCompanyId(companyId);
        request.getReceiver().setCompanyId(companyId);
        request.getShipper().setCompanyId(companyId);

        AddressBookModel oldShipper = addressBookService.getByTel(request.getShipper().getTel());
        if (oldShipper != null) {
            request.getShipper().setId(oldShipper.getId());
            addressBookService.update(request.getShipper());
        } else {
            request.getShipper().setId(null);
            addressBookService.insert(request.getShipper());
        }

        AddressBookModel oldReceiver = addressBookService.getByTel(request.getReceiver().getTel());
        if (oldReceiver != null) {
            request.getReceiver().setId(oldReceiver.getId());
            addressBookService.update(request.getReceiver());
        } else {
            request.getReceiver().setId(null);
            addressBookService.insert(request.getReceiver());
        }

        model.setReceiverId(request.getReceiver().getId());
        model.setShipperId(request.getShipper().getId());
        insert(model);
        return model;
    }

    @Override
    public WaybillModel insertOne(WaybillOneRequest request, Long companyId) {
        WaybillModel model = insert(request, companyId);
        model.setStatus(WaybillStatus.WAIT_PICK);
        List<GoodsModel> goodsList = request.getGoodsDatas();
        if (request.getType().equals(WaybillType.DIRECT)) {
//            request.getCarDriverIds().forEach(item -> bindCarAndDriver(model.getNo(), item.getCarId(), item.getDriverId()));

            request.getCarDriverIds().forEach(item -> {
                CarModel trailerModel = carService.getByCarNumber(item.getTrailerNo());
                if (trailerModel != null) {
                    bindCarTrailerAndDriver(model.getNo(), item.getCarId(), item.getDriverId(), trailerModel.getId());
                } else {
                    bindCarAndDriver(model.getNo(), item.getCarId(), item.getDriverId());
                }

            });
        } /*else {
            List<DriverModel> allDriver = driverService.getAll();
            for (DriverModel item : allDriver) {
                //// TODO: 2019/10/22 微信通知
            }
        }*/
        goodsList.forEach(item -> {
            item.setOrderNo(model.getNo());
            goodsService.insert(item);
        });
        sentToDriver(model.getNo());
        return model;
    }

    @Override
    public void sentToDriver(String orderNo) {
        WaybillModel waybillModel = getByNo(orderNo);
        if (waybillModel == null) {
            throw new CustomException("订单信息不存在");
        }
        /*List<DriverCarEntity> carAndDriverList = getListCarAndDriver(orderNo);
        if (carAndDriverList.size() == 0 && waybillModel.getType().equals(WaybillType.DIRECT)) {
            throw new CustomException("没有指定司机和车辆");
        }
        for (DriverCarEntity item : carAndDriverList) {
            //// TODO: 2019-4-3 推送消息给司机
            System.out.println(String.format("司机[%s]：%s", item.getTel(), item.getRealName()));
        }*/
        waybillModel.setStatus(WaybillStatus.WAIT_PICK);
        update(waybillModel);
    }

    @Override
    public void payMark(String orderNo) {
        WaybillModel waybill = getByNo(orderNo);
        if (waybill == null) {
            throw new CustomException("订单信息不存在!");
        }
        if (!waybill.getStatus().equals(WaybillStatus.WAIT_PAY)) {
            throw new CustomException("订单状态错误");
        }

        waybill.setStatus(WaybillStatus.DONE);
        waybill.setPayTime(new Date());
        update(waybill);

        waybillLogService.insert(orderNo, "运单费用已支付");
    }

    @Override
    public void confirmOrder(String orderNo) {
        WaybillModel waybill = getByNo(orderNo);
        if (waybill == null) {
            throw new CustomException("订单信息不存在");
        }
        if (!waybill.getStatus().equals(WaybillStatus.WAIT_PICK)) {
            throw new CustomException("订单状态错误");
        }

        List<DriverCarEntity> driverCarList = getListCarAndDriver(orderNo);
        if (driverCarList.size() == 0) {
            throw new CustomException("还未指定司机和车辆");
        }

        boolean isSuc = false;
        for (DriverCarEntity item : driverCarList) {
            if (item.getStatus().equals(AcceptedState.ACCEPTED)) {
                isSuc = true;
                break;
            }
        }
        if (!isSuc) {
            throw new CustomException("没有司机和车辆执行此次运输任务");
        }

        waybill.setStatus(WaybillStatus.PICKED);
        waybill.setPickTime(new Date());
        update(waybill);

        List<DriverCarEntity> list = getListCarAndDriver(orderNo);
        for (DriverCarEntity item : list) {
            driverService.changeStatus(item.getDriverId(), DriverStatus.WORKING);
        }

        waybillLogService.insert(orderNo, "系统确认订单信息，开始执行运单");

        //// TODO: 2019-04-06 通知司机

    }

    @Override
    public boolean checkDriver(String orderNo, Long driverId) {
        List<DriverCarEntity> list = getListCarAndDriver(orderNo);
        for (DriverCarEntity item : list) {
            if (item.getDriverId().equals(driverId)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public void accessOrder(String orderNo, Long driverId, Long carId) {
        accessOrder(orderNo, driverId, carId, 0);
    }

    @Override
    public void accessOrder(String orderNo, Long driverId, Long carId, double price) {
        WaybillModel waybill = getByNo(orderNo);
        DriverModel driver = driverService.getById(driverId);
        CarModel car = carService.getById(carId);
        if (driver == null) {
            throw new CustomException("司机信息不存在");
        }

        if (car == null) {
            throw new CustomException("车辆信息不存在");
        }

        if (waybill == null) {
            throw new CustomException("运单信息不存在");
        }

        if (!waybill.getStatus().equals(WaybillStatus.WAIT_PICK)) {
            throw new CustomException("运单状态错误");
        }

        if (waybill.getType().equals(WaybillType.DIRECT) && !checkDriver(orderNo, driverId)) {
            throw new CustomException("接单失败，你不是本运单的计划司机");
        }

        if (waybill.getType().equals(WaybillType.DIRECT)) {
            //// TODO: 2019-04-05 判断是否所有司机都已经接单,如果是，这订单进入到下一个状态
            accessCarAndDriver(orderNo, carId, driverId, price);
            waybill.setPickTime(new Date());
            waybillLogService.insert(orderNo, driver.getRealName() + "接受该订单");
        } else {
            bindCarAndDriver(orderNo, carId, driverId, price);
        }


    }

    @Override
    public void orderStart(String orderNo, Long driverId) {
        WaybillModel waybill = getByNo(orderNo);
        if (waybill == null) {
            throw new CustomException("订单信息不存在");
        }
        if (!waybill.getStatus().equals(WaybillStatus.PICKED)) {
            throw new CustomException("订单状态错误");
        }

        if (!checkDriver(orderNo, driverId)) {
            throw new CustomException("您不是该运单的驾驶员");
        }

        waybill.setStatus(WaybillStatus.IN_TRANSIT);
        waybill.setTransportTime(new Date());
        update(waybill);

        waybillLogService.insert(orderNo, "运单开始运输");

    }

    @Override
    public void orderArrivals(String orderNo, Long driverId) {
        WaybillModel waybill = getByNo(orderNo);
        if (waybill == null) {
            throw new CustomException("订单信息不存在!");
        }

        if (!waybill.getStatus().equals(WaybillStatus.IN_TRANSIT)) {
            throw new CustomException("订单状态错误!");
        }

        if (!checkDriver(orderNo, driverId)) {
            throw new CustomException("您不是该运单的驾驶员");
        }

        waybill.setStatus(WaybillStatus.ARRIVALS);
        update(waybill);

        waybillLogService.insert(orderNo, "货物已经运送到目的地");

    }

    @Override
    public void driverConfirmCode(String orderNo, Long driverId, String code) {
        WaybillModel waybill = getByNo(orderNo);
        if (waybill == null) {
            throw new CustomException("订单信息不存在!");
        }

        if (!waybill.getStatus().equals(WaybillStatus.ARRIVALS)) {
            throw new CustomException("订单状态错误!");
        }

        if (!checkDriver(orderNo, driverId)) {
            throw new CustomException("您不是该运单的驾驶员");
        }

        if (waybill.getCode() == null || !waybill.getCode().equals(code)) {
            throw new CustomException("运单确认码错误");
        }
        waybill.setStatus(WaybillStatus.WAIT_PAY);
        waybill.setDoneTime(new Date());
        update(waybill);

        List<DriverCarEntity> list = getListCarAndDriver(orderNo);
        for (DriverCarEntity item : list) {
            driverService.changeStatus(item.getDriverId(), DriverStatus.IDLE);
        }

        waybillLogService.insert(orderNo, "货物成功交接给货主");

    }

    @Override
    public List<WaybillModel> getPublicList(String orderNo) {
        return waybillDao.getList(orderNo, WaybillType.PUBLIC,
                WaybillStatus.WAIT_PICK,
                WaybillStatus.PICKED,
                WaybillStatus.IN_TRANSIT,
                WaybillStatus.ARRIVALS,
                WaybillStatus.DONE);
    }

    @Override
    public List<WaybillModel> getOwnerList(long driverId, String orderNo, WaybillType type) {
        return waybillDao.getOwnerList(driverId, orderNo, type);
    }

    @Override
    public void insertFile(String orderNo, Long fileId, Long driverId) {
        WaybillModel waybillModel = getByNo(orderNo);
        if (waybillModel == null || !checkDriver(orderNo, driverId)) {
            throw new CustomException("运单信息不存在");
        }

        WaybillFileModel model = new WaybillFileModel();
        model.setOrderNo(orderNo);
        model.setFileId(fileId);
        model.setDriverId(driverId);
        waybillFileDao.insert(model);
    }

    @Override
    public List<WaybillFileModel> getFileList(String orderNo) {
        return waybillFileDao.getFileList(orderNo);
    }

    @Override
    public List<WaybillFileModel> getFileList(String orderNo, Long driverId) {
        return waybillFileDao.getFileListByDriverId(orderNo, driverId);
    }

    @Override
    public void removeFile(long fileId) {
        waybillFileDao.removeFIleByFileId(fileId);
        fileService.delete(fileId);
    }

    @Override
    public List<WaybillModel> getListByCompanyId(Long companyId) {
        return waybillDao.getListByCompanyId(companyId);
    }

    @Override
    public List<Map> getReportList(String dateFormat, Long companyId, Date startTime, Date endTime) {
        return waybillDao.getReportList(dateFormat, companyId, startTime, endTime);
    }

    @Override
    public List<ReportDayCount> getReportCount(Long companyId, String startTime, String endTime, String shipper, String receiver) {
        return waybillDao.getReportCount(companyId, startTime, endTime, shipper, receiver);
    }

    @Override
    public void insert(WaybillModel model) {
        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssS");
        model.setNo(df.format(new Date()));
        model.setCreatedTime(new Date());
        model.setStatus(WaybillStatus.CREATED);
        model.setCode(getRandomCode());
        if (model.getType() == null) {
            model.setType(WaybillType.DIRECT);
        }
        super.insert(model);
        waybillLogService.insert(model.getNo(), "订单创建");
    }

    private String getRandomCode() {
        int n = new Random().nextInt(899999) + 100000;
        return String.valueOf(n);
    }

    @Override
    public List<String> getContinuousDate(String st, String et) {
        List<String> dataList = new ArrayList<>();
        try {
            Date startTime = DateUtils.parseDate(st, "yyyy-MM-dd");
            Date endTime = DateUtils.parseDate(et, "yyyy-MM-dd");
            Date tempDate = startTime;
            while (!DateUtils.isSameDay(tempDate, endTime)) {
                String s = DateFormatUtils.format(tempDate, "yyyy-MM-dd");
                dataList.add(s);
                tempDate = DateUtils.addDays(tempDate, 1);
            }
        } catch (ParseException e) {
            return dataList;
        }
        return dataList;
    }

    @Override
    public List<String> create(String exOrderNo, ExOrderRequest order, long companyId) {
        List<String> orderNoList = new ArrayList<>();
        List<CarModel> carList = carService.getListByCompanyId(companyId);
        double totalWeight = order.getGoodsList().stream().mapToDouble(GoodsModel::getWeights).sum();

        for (CarModel item : carList) {
            totalWeight = totalWeight - item.getMaxLoad();
            if (totalWeight < 0) {
                totalWeight = 0;
            }
            if (totalWeight >= 0) {
                WaybillRequest request = new WaybillRequest();
                order.getShipper().setId(null);
                order.getReceiver().setId(null);
                request.setReceiver(order.getReceiver());
                request.setShipper(order.getShipper());
                request.setType(WaybillType.DIRECT);
                request.setWeight(item.getMaxLoad());
                request.setClaim(order.getClaim());

                WaybillModel waybill = insert(request, companyId);

                List<DriverModel> driverList = carService.getDriverList(item.getId());
                if (driverList.size() > 0) {
                    bindCarAndDriver(waybill.getNo(), item.getId(), driverList.get(0).getId());
                }
                waybill.setStatus(WaybillStatus.WAIT_PICK);
                waybill.setExOrderNo(exOrderNo);
                update(waybill);

                order.getGoodsList().forEach(goods -> {
                    goods.setOrderNo(waybill.getNo());
                    goodsService.insert(goods);
                });

                orderNoList.add(waybill.getNo());
            }
        }
        return orderNoList;
    }

    @Override
    public List<WaybillModel> getWayBillList(String exOrderNo) {
        return waybillDao.getListByExOrderNo(exOrderNo);
    }
}
